﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Nest;

namespace XMK.Framework.ElasticSearch
{
    public class ElasticSearchFilter
    {
        private ElasticSearchFilter(BaseFilter searchDescriptor)
        {
            _filterDescriptor = searchDescriptor;
        }

        private BaseFilter _filterDescriptor;

        public BaseFilter FilterDescriptor
        {
            get
            {
                return _filterDescriptor;
            }
        }

        public static ElasticSearchFilter Eq(string fieldName, object value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Term(fieldName, value.ToString()));
        }

        public static ElasticSearchFilter NotEq(string fieldName, object value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Bool(t2 => t2.MustNot(t3 => t3.Term(fieldName, value.ToString()))));
        }

        public static ElasticSearchFilter Lk(string fieldName, string value)
        {
            return Lk(fieldName, value, "ik");
        }

        public static ElasticSearchFilter Lk(string fieldName, string value, string analyzer)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Query(t2 => t2.QueryString(t3=>t3.Query(value).Operator(Operator.and).Analyzer(analyzer))));
        }

        public static ElasticSearchFilter And(params ElasticSearchFilter[] esFilters)
        {
            IEnumerable<ElasticSearchFilter> queryList = esFilters.Where(item => item != null);
            if (queryList.Count() == 0)
                return null;

            List<Func<FilterDescriptor<dynamic>, BaseFilter>> funcList = new List<Func<FilterDescriptor<dynamic>, BaseFilter>>();
            foreach (var item in queryList)
            {
                funcList.Add(tt => item.FilterDescriptor);
            }

            return new ElasticSearchFilter(Filter<dynamic>.And(funcList.ToArray()));
        }

        public static ElasticSearchFilter Or(params ElasticSearchFilter[] esFilters)
        {
            IEnumerable<ElasticSearchFilter> queryList = esFilters.Where(item => item != null);
            if (queryList.Count() == 0)
                return null;

            List<Func<FilterDescriptor<dynamic>, BaseFilter>> funcList = new List<Func<FilterDescriptor<dynamic>, BaseFilter>>();
            foreach (var item in queryList)
            {
                funcList.Add(tt => item.FilterDescriptor);
            }

            return new ElasticSearchFilter(Filter<dynamic>.Or(funcList.ToArray()));
        }

        public static ElasticSearchFilter In(string fieldName, IEnumerable<string> values)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Terms(fieldName, values));
        }

        public static ElasticSearchFilter Between(string fieldName, int? from, int? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchFilter Between(string fieldName, double? from, double? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchFilter Between(string fieldName, DateTime? from, DateTime? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchFilter Gt(string fieldName, int value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchFilter Gt(string fieldName, double value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchFilter Gt(string fieldName, DateTime value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchFilter Gte(string fieldName, int value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchFilter Gte(string fieldName, double value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchFilter Gte(string fieldName, DateTime value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchFilter Lt(string fieldName, int value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchFilter Lt(string fieldName, double value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchFilter Lt(string fieldName, DateTime value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchFilter Lte(string fieldName, int value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }

        public static ElasticSearchFilter Lte(string fieldName, double value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }

        public static ElasticSearchFilter Lte(string fieldName, DateTime value)
        {
            return new ElasticSearchFilter(Filter<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }
    }
}
